/**
 * 测量工具模块
 * @description 提供地图上的测量功能，包括距离、面积、高度等测量工具
 */

import { ref, reactive } from 'vue';

/**
 * 测量工具类
 * @class MeasureTools
 */
export class MeasureTools {
  constructor(mapEngine) {
    this.mapEngine = mapEngine;
    this.measureThing = null;
    this.measureLayer = null;
    this.currentTool = null;
    this.isMeasuring = false;
    
    // 测量配置
    this.measureConfig = reactive({
      style: {
        point: {
          pixelSize: 12,
          color: '#ff0000',
          outlineColor: '#ffffff',
          outlineWidth: 2
        },
        line: {
          color: '#ffff00',
          width: 3,
          clampToGround: true
        },
        polygon: {
          color: 'rgba(255,255,0,0.3)',
          outline: true,
          outlineColor: '#ffff00',
          outlineWidth: 2
        },
        label: {
          color: '#ffffff',
          font_size: 16,
          font_family: '微软雅黑',
          background: true,
          backgroundColor: 'rgba(0,0,0,0.7)',
          padding: [5, 10],
          borderRadius: 3
        }
      },
      units: {
        distance: 'm', // m, km, ft, mi
        area: 'm²',    // m², km², ft², acre
        angle: '°'     // °, rad
      },
      precision: {
        distance: 2,
        area: 2,
        angle: 1
      }
    });

    // 测量结果存储
    this.measurements = new Map();
    this.measurementId = 0;

    // 事件回调
    this.callbacks = {
      onMeasureStart: null,
      onMeasuring: null,
      onMeasureEnd: null,
      onMeasureCancel: null
    };

    this.init();
  }

  /**
   * 初始化测量工具
   * @private
   */
  init() {
    const map = this.mapEngine?.getInstance();
    if (!map) return;

    // 创建测量图层
    this.measureLayer = new mars3d.layer.GraphicLayer({
      name: "测量图层",
      id: "measure_layer"
    });
    map.addLayer(this.measureLayer);

    // 创建测量对象
    this.measureThing = new mars3d.thing.Measure({
      label: this.measureConfig.style.label,
      isAutoEditing: false // 禁用自动编辑
    });
    map.addThing(this.measureThing);

    // 绑定测量事件
    this._bindMeasureEvents();

    // 设置编辑点样式
    mars3d.DrawUtil.setAllEditPointStyle(this.measureConfig.style.point);
  }

  /**
   * 绑定测量事件
   * @private
   */
  _bindMeasureEvents() {
    if (!this.measureThing) return;

    // 测量开始事件
    this.measureThing.on(mars3d.EventType.start, (event) => {
      this.isMeasuring = true;
      this._triggerCallback('onMeasureStart', {
        type: this.currentTool,
        event
      });
    });

    // 测量过程事件
    this.measureThing.on(mars3d.EventType.drawAddPoint, (event) => {
      this._triggerCallback('onMeasuring', {
        type: this.currentTool,
        event,
        currentValue: this._getCurrentMeasureValue(event)
      });
    });

    // 测量完成事件
    this.measureThing.on(mars3d.EventType.drawCreated, (event) => {
      this.isMeasuring = false;
      const result = this._processMeasureResult(event);
      this._saveMeasurement(result);
      
      this._triggerCallback('onMeasureEnd', result);
    });

    // 测量停止事件
    this.measureThing.on(mars3d.EventType.drawStop, (_event) => {
      this.isMeasuring = false;
      this.currentTool = null;
    });
  }

  /**
   * 测量距离
   * @param {Object} options - 测量选项
   * @param {Function} options.callback - 完成回调
   * @returns {Promise} 测量结果
   */
  async measureDistance(options = {}) {
    const { callback } = options;
    
    return this._startMeasure('distance', {
      type: 'distanceSurfaceMeasure',
      style: {
        ...this.measureConfig.style.line,
        label: {
          ...this.measureConfig.style.label,
          text: '{measure}'
        }
      }
    }, callback);
  }

  /**
   * 测量面积
   * @param {Object} options - 测量选项
   * @param {Function} options.callback - 完成回调
   * @returns {Promise} 测量结果
   */
  async measureArea(options = {}) {
    const { callback } = options;
    
    return this._startMeasure('area', {
      type: 'areaSurfaceMeasure',
      style: {
        ...this.measureConfig.style.polygon,
        label: {
          ...this.measureConfig.style.label,
          text: '{measure}'
        }
      }
    }, callback);
  }

  /**
   * 测量高度
   * @param {Object} options - 测量选项
   * @param {Function} options.callback - 完成回调
   * @returns {Promise} 测量结果
   */
  async measureHeight(options = {}) {
    const { callback } = options;
    
    return this._startMeasure('height', {
      type: 'heightMeasure',
      style: {
        ...this.measureConfig.style.line,
        label: {
          ...this.measureConfig.style.label,
          text: '{measure}'
        }
      }
    }, callback);
  }

  /**
   * 测量角度
   * @param {Object} options - 测量选项
   * @param {Function} options.callback - 完成回调
   * @returns {Promise} 测量结果
   */
  async measureAngle(options = {}) {
    const { callback } = options;
    
    return this._startMeasure('angle', {
      type: 'angleMeasure',
      style: {
        ...this.measureConfig.style.line,
        label: {
          ...this.measureConfig.style.label,
          text: '{measure}'
        }
      }
    }, callback);
  }

  /**
   * 测量坐标点
   * @param {Object} options - 测量选项
   * @param {Function} options.callback - 完成回调
   * @returns {Promise} 测量结果
   */
  async measurePoint(options = {}) {
    const { callback } = options;
    
    return this._startMeasure('point', {
      type: 'pointMeasure',
      style: {
        ...this.measureConfig.style.point,
        label: {
          ...this.measureConfig.style.label,
          text: '{measure}'
        }
      }
    }, callback);
  }

  /**
   * 通用测量方法
   * @private
   * @param {string} type - 测量类型
   * @param {Object} config - 测量配置
   * @param {Function} callback - 完成回调
   * @returns {Promise} 测量结果
   */
  async _startMeasure(type, config, callback) {
    if (this.isMeasuring) {
      this.stopMeasure();
    }

    this.currentTool = type;

    try {
      // 开始测量
      const result = await this.measureThing.measure(config);
      
      if (callback) {
        callback(result);
      }

      return result;

    } catch (error) {
      console.error('Measure error:', error);
      this._triggerCallback('onMeasureCancel', { type, error });
      throw error;
    }
  }

  /**
   * 获取当前测量值
   * @private
   * @param {Object} event - 测量事件
   * @returns {Object} 当前测量值
   */
  _getCurrentMeasureValue(event) {
    const graphic = event.graphic;
    if (!graphic) return null;

    const result = {
      type: this.currentTool,
      value: null,
      unit: null,
      formatted: null
    };

    try {
      switch (this.currentTool) {
        case 'distance':
          result.value = graphic.distance;
          result.unit = this.measureConfig.units.distance;
          result.formatted = mars3d.MeasureUtil.formatDistance(
            result.value,
            this.measureConfig.precision.distance
          );
          break;
        
        case 'area':
          result.value = graphic.area;
          result.unit = this.measureConfig.units.area;
          result.formatted = mars3d.MeasureUtil.formatArea(
            result.value,
            this.measureConfig.precision.area
          );
          break;
        
        case 'height':
          result.value = graphic.height;
          result.unit = 'm';
          result.formatted = `${result.value.toFixed(this.measureConfig.precision.distance)}m`;
          break;
        
        case 'angle':
          result.value = graphic.angle;
          result.unit = this.measureConfig.units.angle;
          result.formatted = `${result.value.toFixed(this.measureConfig.precision.angle)}°`;
          break;
        
        case 'point':
          if (graphic.position) {
            const cartographic = mars3d.Cartographic.fromCartesian(graphic.position);
            result.value = {
              lng: mars3d.Math.toDegrees(cartographic.longitude),
              lat: mars3d.Math.toDegrees(cartographic.latitude),
              alt: cartographic.height
            };
            result.formatted = this._formatCoordinates(result.value);
          }
          break;
      }
    } catch (error) {
      console.warn('Failed to get current measure value:', error);
    }

    return result;
  }

  /**
   * 处理测量结果
   * @private
   * @param {Object} event - 测量完成事件
   * @returns {Object} 处理后的测量结果
   */
  _processMeasureResult(event) {
    const graphic = event.graphic;
    const measureId = ++this.measurementId;
    
    const result = {
      id: measureId,
      type: this.currentTool,
      graphic,
      timestamp: new Date(),
      ...this._getCurrentMeasureValue(event)
    };

    // 添加额外的几何信息
    if (graphic.positions) {
      result.coordinates = this._extractCoordinates(graphic.positions);
    } else if (graphic.position) {
      result.coordinates = this._extractCoordinates([graphic.position]);
    }

    return result;
  }

  /**
   * 提取坐标信息
   * @private
   * @param {Array} positions - 位置数组
   * @returns {Array} 坐标数组
   */
  _extractCoordinates(positions) {
    return positions.map(pos => {
      const cartographic = mars3d.Cartographic.fromCartesian(pos);
      return {
        lng: mars3d.Math.toDegrees(cartographic.longitude),
        lat: mars3d.Math.toDegrees(cartographic.latitude),
        alt: cartographic.height
      };
    });
  }

  /**
   * 格式化坐标
   * @private
   * @param {Object} coord - 坐标对象
   * @returns {string} 格式化的坐标字符串
   */
  _formatCoordinates(coord) {
    const { lng, lat, alt } = coord;
    return `经度: ${lng.toFixed(6)}°\n纬度: ${lat.toFixed(6)}°\n高度: ${alt.toFixed(2)}m`;
  }

  /**
   * 保存测量结果
   * @private
   * @param {Object} result - 测量结果
   */
  _saveMeasurement(result) {
    this.measurements.set(result.id, result);
  }

  /**
   * 停止当前测量
   */
  stopMeasure() {
    if (!this.isMeasuring) return;

    try {
      this.measureThing?.stop();
      this.isMeasuring = false;
      this.currentTool = null;
      this._triggerCallback('onMeasureCancel', { reason: 'manual_stop' });
    } catch (error) {
      console.warn('Failed to stop measuring:', error);
    }
  }

  /**
   * 清除所有测量结果
   */
  clearAll() {
    try {
      this.measureThing?.clear();
      this.measurements.clear();
      this.measurementId = 0;
    } catch (error) {
      console.warn('Failed to clear measurements:', error);
    }
  }

  /**
   * 删除指定测量结果
   * @param {number|Object} measurement - 测量ID或测量对象
   */
  removeMeasurement(measurement) {
    try {
      let id, graphic;
      
      if (typeof measurement === 'number') {
        id = measurement;
        const result = this.measurements.get(id);
        graphic = result?.graphic;
      } else if (measurement && measurement.id) {
        id = measurement.id;
        graphic = measurement.graphic;
      } else {
        graphic = measurement;
        // 查找对应的ID
        for (const [key, value] of this.measurements.entries()) {
          if (value.graphic === graphic) {
            id = key;
            break;
          }
        }
      }

      if (graphic) {
        this.measureThing?.removeGraphic(graphic);
      }
      
      if (id) {
        this.measurements.delete(id);
      }
    } catch (error) {
      console.warn('Failed to remove measurement:', error);
    }
  }

  /**
   * 获取所有测量结果
   * @returns {Array} 测量结果数组
   */
  getAllMeasurements() {
    return Array.from(this.measurements.values());
  }

  /**
   * 获取指定类型的测量结果
   * @param {string} type - 测量类型
   * @returns {Array} 指定类型的测量结果
   */
  getMeasurementsByType(type) {
    return this.getAllMeasurements().filter(result => result.type === type);
  }

  /**
   * 导出测量结果
   * @param {string} format - 导出格式 ('json' | 'csv' | 'geojson')
   * @returns {string|Object} 导出的数据
   */
  exportMeasurements(format = 'json') {
    const measurements = this.getAllMeasurements();
    
    switch (format.toLowerCase()) {
      case 'json':
        return JSON.stringify(measurements, null, 2);
      
      case 'csv':
        return this._exportToCSV(measurements);
      
      case 'geojson':
        return this._exportToGeoJSON(measurements);
      
      default:
        throw new Error(`Unsupported export format: ${format}`);
    }
  }

  /**
   * 导出为CSV格式
   * @private
   * @param {Array} measurements - 测量结果数组
   * @returns {string} CSV字符串
   */
  _exportToCSV(measurements) {
    if (measurements.length === 0) return '';

    const headers = ['ID', '类型', '值', '单位', '时间'];
    const rows = measurements.map(result => [
      result.id,
      result.type,
      typeof result.value === 'object' ? JSON.stringify(result.value) : result.value,
      result.unit || '',
      result.timestamp.toISOString()
    ]);

    return [headers, ...rows]
      .map(row => row.map(cell => `"${cell}"`).join(','))
      .join('\n');
  }

  /**
   * 导出为GeoJSON格式
   * @private
   * @param {Array} measurements - 测量结果数组
   * @returns {Object} GeoJSON对象
   */
  _exportToGeoJSON(measurements) {
    const features = measurements
      .filter(result => result.coordinates)
      .map(result => {
        let geometry;
        
        if (result.type === 'point') {
          geometry = {
            type: 'Point',
            coordinates: [result.coordinates[0].lng, result.coordinates[0].lat]
          };
        } else if (result.type === 'distance' || result.type === 'height') {
          geometry = {
            type: 'LineString',
            coordinates: result.coordinates.map(coord => [coord.lng, coord.lat])
          };
        } else if (result.type === 'area') {
          geometry = {
            type: 'Polygon',
            coordinates: [result.coordinates.map(coord => [coord.lng, coord.lat])]
          };
        }

        return {
          type: 'Feature',
          geometry,
          properties: {
            id: result.id,
            measureType: result.type,
            value: result.value,
            unit: result.unit,
            formatted: result.formatted,
            timestamp: result.timestamp.toISOString()
          }
        };
      });

    return {
      type: 'FeatureCollection',
      features
    };
  }

  /**
   * 设置测量配置
   * @param {Object} config - 配置对象
   */
  setConfig(config) {
    Object.assign(this.measureConfig, config);
    
    // 更新测量对象的标签样式
    if (this.measureThing && config.style?.label) {
      this.measureThing.label = { ...this.measureConfig.style.label };
    }
  }

  /**
   * 设置事件回调
   * @param {string} event - 事件名称
   * @param {Function} callback - 回调函数
   */
  on(event, callback) {
    const callbackName = `on${event.charAt(0).toUpperCase()}${event.slice(1)}`;
    if (this.callbacks.hasOwnProperty(callbackName)) {
      this.callbacks[callbackName] = callback;
    }
  }

  /**
   * 触发回调
   * @private
   * @param {string} callbackName - 回调名称
   * @param {any} data - 回调数据
   */
  _triggerCallback(callbackName, data) {
    const callback = this.callbacks[callbackName];
    if (typeof callback === 'function') {
      try {
        callback(data);
      } catch (error) {
        console.error(`Error in ${callbackName} callback:`, error);
      }
    }
  }

  /**
   * 获取测量状态
   * @returns {Object} 测量状态信息
   */
  getMeasureStatus() {
    return {
      isMeasuring: this.isMeasuring,
      currentTool: this.currentTool,
      measurementCount: this.measurements.size,
      config: { ...this.measureConfig }
    };
  }

  /**
   * 销毁测量工具
   */
  destroy() {
    this.stopMeasure();
    this.clearAll();
    
    const map = this.mapEngine?.getInstance();
    if (map) {
      if (this.measureThing) {
        map.removeThing(this.measureThing);
      }
      if (this.measureLayer) {
        map.removeLayer(this.measureLayer, true);
      }
    }

    this.measureThing = null;
    this.measureLayer = null;
    this.mapEngine = null;
    this.measurements.clear();
    this.callbacks = {};
  }
}

/**
 * 测量工具组合函数
 * @param {Object} mapEngine - 地图引擎实例
 * @returns {Object} 测量工具API
 */
export function useMeasureTools(mapEngine) {
  const measureTools = ref(null);

  /**
   * 初始化测量工具
   */
  const initMeasureTools = () => {
    measureTools.value = new MeasureTools(mapEngine);
    return measureTools.value;
  };

  /**
   * 获取测量工具实例
   */
  const getMeasureTools = () => measureTools.value;

  /**
   * 销毁测量工具
   */
  const destroy = () => {
    if (measureTools.value) {
      measureTools.value.destroy();
      measureTools.value = null;
    }
  };

  return {
    measureTools,
    initMeasureTools,
    getMeasureTools,
    destroy
  };
}
